package com.nulldev.util.networking.async2.tcp.client.packets;

import java.util.concurrent.RejectedExecutionException;

import com.nulldev.util.networking.async2.DataFrame;
import com.nulldev.util.networking.async2.events.ManualResetEvent;
import com.nulldev.util.networking.async2.tcp.client.connectors.TCPConnector;

public final class IncomingTCPClientPacket implements Runnable {

	public ManualResetEvent fDone = new ManualResetEvent(false);
	private final TCPConnector fConnector;
	private final DataFrame fData;
	private IncomingTCPClientPacket fPreviousPacket;
	public boolean fCancel = false;

	/**
	 * Constructs a new incoming packet received by a TCP connector.
	 *
	 * Use this class to receive data from a server. This is an incoming message
	 * that will remain in the client's thread pool as a job for the thread pool
	 * workers.
	 *
	 * @param connector      is the TCP Connector where this message belongs to.
	 * @param data           is a DataFrame class.
	 * @param previousPacket is the previous incoming message of the TCP Connector.
	 */
	public IncomingTCPClientPacket(TCPConnector connector, DataFrame data, IncomingTCPClientPacket previousPacket) {
		fConnector = connector;
		fData = data;
		fPreviousPacket = previousPacket;

		sendToThreadPool();
	}

	protected void sendToThreadPool() {
		try {
			fConnector.fMyTCPClient.fMyThreadPool.execute(this);
		} catch (RejectedExecutionException ex) {
			fConnector.forceStop();
		}
	}

	/**
	 * Cancel this incoming packet.
	 *
	 * By calling this method this and all the previous incoming packets that are
	 * stored in the thread pool will be canceled. Call this method for the last
	 * incoming packet of the TCP Connector when the TCP Connector disconnects.
	 *
	 */
	public void cancel() {
		fCancel = true;
		fDone.set();
	}

	@Override
	public void run() {
		try {
			if (fPreviousPacket == null) {
				fConnector.fMyTCPClient.onDataReceive(fConnector, fData);
			} else {
				fPreviousPacket.fDone.waitOne();
				if (!fCancel && !fPreviousPacket.fCancel) {
					fConnector.fMyTCPClient.onDataReceive(fConnector, fData);
				} else {
					fCancel = true;
				}
			}
		} catch (Exception ex) {
		}

		if (fPreviousPacket != null) {
			fPreviousPacket = null;
		}

		fDone.set();
	}

	/**
	 * Returns the data of this packet.
	 *
	 * @return the data of this packet.
	 */
	public DataFrame getData() {
		return fData;
	}

	/**
	 * Returns the previus incoming packet received by the client. If the packet is
	 * null means that the packet has been received and parsed from the client.
	 *
	 * @return the previus incoming packet received by the client.
	 */
	public IncomingTCPClientPacket getPreviusPacket() {
		return fPreviousPacket;
	}
}